فارسی

قدرت سربارگذاری توابع تایپ‌اسکریپت را برای ایجاد توابع انعطاف‌پذیر و امن از نظر نوع با تعاریف امضای چندگانه آزاد کنید. با مثال‌های واضح و بهترین شیوه‌ها بیاموزید.

سربارگذاری توابع در تایپ‌اسکریپت: تسلط بر تعاریف چندگانه امضا

تایپ‌اسکریپت، که یک اَبَرمجموعه از جاوااسکریپت است، ویژگی‌های قدرتمندی برای بهبود کیفیت و قابلیت نگهداری کد ارائه می‌دهد. یکی از باارزش‌ترین و در عین حال گاهی بدفهمیده شده‌ترین ویژگی‌ها، سربارگذاری توابع (function overloading) است. سربارگذاری توابع به شما امکان می‌دهد تا چندین تعریف امضا برای یک تابع تعریف کنید، که این امر به آن تابع اجازه می‌دهد تا انواع و تعداد مختلفی از آرگومان‌ها را با امنیت نوع دقیق مدیریت کند. این مقاله یک راهنمای جامع برای درک و استفاده مؤثر از سربارگذاری توابع در تایپ‌اسکریپت ارائه می‌دهد.

سربارگذاری توابع چیست؟

در اصل، سربارگذاری توابع به شما امکان می‌دهد تابعی با نام یکسان اما با لیست پارامترهای متفاوت (یعنی تعداد، نوع یا ترتیب متفاوت پارامترها) و به طور بالقوه انواع بازگشتی متفاوت تعریف کنید. کامپایلر تایپ‌اسکریپت از این امضاهای متعدد استفاده می‌کند تا مناسب‌ترین امضای تابع را بر اساس آرگومان‌های ارسال شده هنگام فراخوانی تابع تعیین کند. این امر انعطاف‌پذیری و امنیت نوع بیشتری را هنگام کار با توابعی که نیاز به مدیریت ورودی‌های متغیر دارند، فراهم می‌کند.

این ویژگی را مانند یک خط تلفن خدمات مشتری در نظر بگیرید. بسته به آنچه شما می‌گویید، سیستم خودکار شما را به بخش صحیح هدایت می‌کند. سیستم سربارگذاری تایپ‌اسکریپت نیز همین کار را برای فراخوانی‌های توابع شما انجام می‌دهد.

چرا از سربارگذاری توابع استفاده کنیم؟

استفاده از سربارگذاری توابع چندین مزیت دارد:

سینتکس و ساختار پایه

یک سربارگذاری تابع شامل چندین اعلان امضا (signature declarations) است که به دنبال آن یک پیاده‌سازی (implementation) واحد قرار می‌گیرد که تمام امضاهای اعلام شده را مدیریت می‌کند.

ساختار کلی به شرح زیر است:


// امضای ۱
function myFunction(param1: type1, param2: type2): returnType1;

// امضای ۲
function myFunction(param1: type3): returnType2;

// امضای پیاده‌سازی (از بیرون قابل مشاهده نیست)
function myFunction(param1: type1 | type3, param2?: type2): returnType1 | returnType2 {
  // منطق پیاده‌سازی در اینجا
  // باید تمام ترکیب‌های ممکن امضاها را مدیریت کند
}

ملاحظات مهم:

مثال‌های عملی

بیایید سربارگذاری توابع را با چند مثال عملی نشان دهیم.

مثال ۱: ورودی رشته یا عدد

تابعی را در نظر بگیرید که می‌تواند یک رشته یا یک عدد را به عنوان ورودی بگیرد و یک مقدار تبدیل شده بر اساس نوع ورودی بازگرداند.


// امضاهای سربارگذاری
function processValue(value: string): string;
function processValue(value: number): number;

// پیاده‌سازی
function processValue(value: string | number): string | number {
  if (typeof value === 'string') {
    return value.toUpperCase();
  } else {
    return value * 2;
  }
}

// کاربرد
const stringResult = processValue("hello"); // stringResult: string
const numberResult = processValue(10);    // numberResult: number

console.log(stringResult); // خروجی: HELLO
console.log(numberResult); // خروجی: 20

در این مثال، ما دو امضای سربارگذاری برای `processValue` تعریف می‌کنیم: یکی برای ورودی رشته و دیگری برای ورودی عدد. تابع پیاده‌سازی هر دو حالت را با استفاده از بررسی نوع مدیریت می‌کند. کامپایلر تایپ‌اسکریپت نوع بازگشتی صحیح را بر اساس ورودی ارائه شده در هنگام فراخوانی تابع استنتاج می‌کند و امنیت نوع را افزایش می‌دهد.

مثال ۲: تعداد آرگومان‌های متفاوت

بیایید تابعی ایجاد کنیم که بتواند نام کامل یک شخص را بسازد. این تابع می‌تواند یا یک نام و یک نام خانوادگی را بپذیرد، یا یک رشته نام کامل را.


// امضاهای سربارگذاری
function createFullName(firstName: string, lastName: string): string;
function createFullName(fullName: string): string;

// پیاده‌سازی
function createFullName(firstName: string, lastName?: string): string {
  if (lastName) {
    return `${firstName} ${lastName}`;
  } else {
    return firstName; // فرض می‌شود firstName در واقع همان fullName است
  }
}

// کاربرد
const fullName1 = createFullName("John", "Doe");  // fullName1: string
const fullName2 = createFullName("Jane Smith"); // fullName2: string

console.log(fullName1); // خروجی: John Doe
console.log(fullName2); // خروجی: Jane Smith

در اینجا، تابع `createFullName` برای مدیریت دو سناریو سربارگذاری شده است: ارائه نام و نام خانوادگی به صورت جداگانه، یا ارائه یک نام کامل. پیاده‌سازی از یک پارامتر اختیاری `lastName?` برای سازگاری با هر دو حالت استفاده می‌کند. این کار یک API تمیزتر و شهودی‌تر برای کاربران فراهم می‌کند.

مثال ۳: مدیریت پارامترهای اختیاری

تابعی را در نظر بگیرید که یک آدرس را قالب‌بندی می‌کند. این تابع ممکن است خیابان، شهر و کشور را بپذیرد، اما کشور ممکن است اختیاری باشد (مثلاً برای آدرس‌های محلی).


// امضاهای سربارگذاری
function formatAddress(street: string, city: string, country: string): string;
function formatAddress(street: string, city: string): string;

// پیاده‌سازی
function formatAddress(street: string, city: string, country?: string): string {
  if (country) {
    return `${street}, ${city}, ${country}`;
  } else {
    return `${street}, ${city}`;
  }
}

// کاربرد
const fullAddress = formatAddress("123 Main St", "Anytown", "USA"); // fullAddress: string
const localAddress = formatAddress("456 Oak Ave", "Springfield");      // localAddress: string

console.log(fullAddress);  // خروجی: 123 Main St, Anytown, USA
console.log(localAddress); // خروجی: 456 Oak Ave, Springfield

این سربارگذاری به کاربران اجازه می‌دهد تا `formatAddress` را با یا بدون کشور فراخوانی کنند، که یک API انعطاف‌پذیرتر فراهم می‌کند. پارامتر `country?` در پیاده‌سازی آن را اختیاری می‌کند.

مثال ۴: کار با اینترفیس‌ها و انواع یونیون

بیایید سربارگذاری توابع را با اینترفیس‌ها و انواع یونیون نشان دهیم، که یک شیء پیکربندی را شبیه‌سازی می‌کند که می‌تواند ویژگی‌های مختلفی داشته باشد.


interface Square {
  kind: "square";
  size: number;
}

interface Rectangle {
  kind: "rectangle";
  width: number;
  height: number;
}

type Shape = Square | Rectangle;

// امضاهای سربارگذاری
function getArea(shape: Square): number;
function getArea(shape: Rectangle): number;

// پیاده‌سازی
function getArea(shape: Shape): number {
  switch (shape.kind) {
    case "square":
      return shape.size * shape.size;
    case "rectangle":
      return shape.width * shape.height;
  }
}

// کاربرد
const square: Square = { kind: "square", size: 5 };
const rectangle: Rectangle = { kind: "rectangle", width: 4, height: 6 };

const squareArea = getArea(square);       // squareArea: number
const rectangleArea = getArea(rectangle); // rectangleArea: number

console.log(squareArea);    // خروجی: 25
console.log(rectangleArea); // خروجی: 24

این مثال از اینترفیس‌ها و یک نوع یونیون برای نمایش انواع مختلف شکل‌ها استفاده می‌کند. تابع `getArea` برای مدیریت هر دو شکل `Square` و `Rectangle` سربارگذاری شده است و امنیت نوع را بر اساس ویژگی `shape.kind` تضمین می‌کند.

بهترین شیوه‌ها برای استفاده از سربارگذاری توابع

برای استفاده مؤثر از سربارگذاری توابع، بهترین شیوه‌های زیر را در نظر بگیرید:

اشتباهات رایج برای اجتناب

سناریوهای پیشرفته

استفاده از جنریک‌ها با سربارگذاری توابع

شما می‌توانید جنریک‌ها را با سربارگذاری توابع ترکیب کنید تا توابع انعطاف‌پذیرتر و امن‌تری از نظر نوع ایجاد کنید. این کار زمانی مفید است که نیاز به حفظ اطلاعات نوع در امضاهای مختلف سربارگذاری دارید.


// امضاهای سربارگذاری با جنریک‌ها
function processArray(arr: T[]): T[];
function processArray(arr: T[], transform: (item: T) => U): U[];

// پیاده‌سازی
function processArray(arr: T[], transform?: (item: T) => U): (T | U)[] {
  if (transform) {
    return arr.map(transform);
  } else {
    return arr;
  }
}

// کاربرد
const numbers = [1, 2, 3];
const doubledNumbers = processArray(numbers, (x) => x * 2); // doubledNumbers: number[]
const strings = processArray(numbers, (x) => x.toString());   // strings: string[]
const originalNumbers = processArray(numbers);                  // originalNumbers: number[]

console.log(doubledNumbers);  // خروجی: [2, 4, 6]
console.log(strings);         // خروجی: ['1', '2', '3']
console.log(originalNumbers); // خروجی: [1, 2, 3]

در این مثال، تابع `processArray` سربارگذاری شده است تا یا آرایه اصلی را بازگرداند یا یک تابع تبدیل را بر روی هر عنصر اعمال کند. از جنریک‌ها برای حفظ اطلاعات نوع در امضاهای مختلف سربارگذاری استفاده می‌شود.

جایگزین‌های سربارگذاری توابع

در حالی که سربارگذاری توابع قدرتمند است، رویکردهای جایگزینی وجود دارند که ممکن است در شرایط خاص مناسب‌تر باشند:

نتیجه‌گیری

سربارگذاری توابع در تایپ‌اسکریپت ابزاری باارزش برای ایجاد توابع انعطاف‌پذیر، امن از نظر نوع و به خوبی مستند شده است. با تسلط بر سینتکس، بهترین شیوه‌ها و اشتباهات رایج، می‌توانید از این ویژگی برای بهبود کیفیت و قابلیت نگهداری کد تایپ‌اسکریپت خود بهره ببرید. به یاد داشته باشید که جایگزین‌ها را در نظر بگیرید و رویکردی را انتخاب کنید که به بهترین شکل با نیازمندی‌های خاص پروژه شما مطابقت دارد. با برنامه‌ریزی و پیاده‌سازی دقیق، سربارگذاری توابع می‌تواند به یک دارایی قدرتمند در جعبه ابزار توسعه تایپ‌اسکریپت شما تبدیل شود.

این مقاله یک مرور جامع از سربارگذاری توابع ارائه داده است. با درک اصول و تکنیک‌های مورد بحث، می‌توانید با اطمینان از آنها در پروژه‌های خود استفاده کنید. با مثال‌های ارائه شده تمرین کنید و سناریوهای مختلف را برای به دست آوردن درک عمیق‌تری از این ویژگی قدرتمند بررسی کنید.